package authorization;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import virtualHD.FileHandler;
import virtualHD.VirtualHD;
import virtualHD.VirtualHDException;

import jaxb.messages.*;

import com.sun.xacml.ctx.Result;


/**
 * As the name suggest it is the master of a certain folder. It actually acts on beahlf of connected 
 * user: if user wants to upload a file it puts that file on that folder, 
 * if user wants to see another folder's contents it asks for contents.
 * Though it does all the work, FolderMaster has to ask for permission to interested folder's
 * ResourceManager.
 * @author pasquale
 *
 */
public class FolderMaster implements VirtualHD{

	public static final String ROOT_DIR = "user_folders/";

	//operations
	public static final String VIEW = "VIEW";
	public static final String PUT = "PUT";
	public static final String GET = "GET";
	public static final String DEL = "DEL";

	public FolderMaster(ResourceManager[] managers,String folder,FileHandler handler){
		this.managers = managers;
		this.folder = folder;
		this.fileHandler = handler;
	}

	@Override
	public void openHD(String userid, String password) throws VirtualHDException {

	}

	@Override
	public Resource[] view(Folder f) throws VirtualHDException {
		Resource resources[] = null;
		checkForPermissions(f.getUserid(),VIEW); //throws VirtualHDException
		//gets a list of every file contained in the directory
		File fileList[] = (new File(ROOT_DIR+f.getUserid())).listFiles(new FileFilter(){
			@Override
			public boolean accept(File arg0) {
				return !(arg0.isHidden());
			}		
		});

		resources = new Resource[fileList.length];
		for(int i=0;i<resources.length;i++)
			resources[i] = new Resource(fileList[i].getName(), fileList[i].lastModified(), fileList[i].length());

		return resources;
	}

	@Override
	public void put(Folder f, Resource resource) throws VirtualHDException {
		int mIndex = checkForPermissions(f.getUserid(),PUT);
		synchronized(managers[mIndex]){
			FileOutputStream outStream;
			try {
				outStream = new FileOutputStream(
						ROOT_DIR+
						f.getUserid()+"/"+resource.getName());
				fileHandler.receiveFile(outStream);
				outStream.close();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}

		}
	}

	@Override
	public void get(Folder f, Resource resource) throws VirtualHDException {
		int mIndex = checkForPermissions(f.getUserid(),GET);
		synchronized(managers[mIndex]){
			FileInputStream inStream;
			try {
				inStream = new FileInputStream(ROOT_DIR+f.getUserid()+"/"+resource.getName());
				fileHandler.sendFile(inStream);
				inStream.close();
			} catch (FileNotFoundException e) {
				throw new VirtualHDException(e.getMessage());
			} catch (IOException e) {
				throw new VirtualHDException(e.getMessage());
			}
		}
	}

	@Override
	public void del(Folder f, Resource resource) throws VirtualHDException {
		int mIndex = checkForPermissions(f.getUserid(),DEL);
		synchronized(managers[mIndex]){
			File file = new File(ROOT_DIR+f.getUserid()+"/"+resource.getName());
			if(file.exists())
				file.delete();
			else
				throw new VirtualHDException("Requested file was not found!");

		}
	}

	@Override
	public void change_role(Folder folder) throws VirtualHDException {
		int mIndex = this.searchForManager(folder.getUserid());
		managers[mIndex].changeRole(folder);

	}

	@Override
	public void closeHD() throws VirtualHDException {
		// TODO Auto-generated method stub

	}

	/**
	 * An utility function which searches for a folder's manager
	 * @param folder
	 * @return 
	 */
	private int searchForManager(String folder){
		int index = -1;
		int i = 0;
		while((index == -1) && (i<managers.length))
			if(managers[i].getFolderName().equals(folder))
				index = i;
			else
				i++;	
		return index;
	}

	/**
	 * An utility function which checks for permissions on a given folder
	 * @param targetFolder
	 * @param action
	 * @return folder manager index
	 */
	private int checkForPermissions(String targetFolder,String action) throws VirtualHDException{
		int index = searchForManager(targetFolder); // we search for the folder's manager
		if(index != -1){ //if there's a folder with that name
			Integer permit = managers[index].askForAuth(folder, ROOT_DIR+targetFolder, action);
			if((permit != null) && (permit == Result.DECISION_PERMIT))
				return index;
			else
				throw new VirtualHDException("You don't have enough permits to do requested operation!");

		}else
			throw new VirtualHDException("Could not find requested folder!");
	}

	private ResourceManager[] managers;
	private String folder;
	private FileHandler fileHandler;

}
